#include "fusexmp.h"
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <errno.h>
#include <sys/time.h>
#include "log.h"


int xmp_getattr(const char *path, struct stat *stbuf)
{	
	//LOG << "path = " << path << ENDL;
	int res = lstat(path, stbuf);
	if (res == -1)
		return -errno;
	return 0;
}

int xmp_access(const char *path, int mask)
{
	//LOG << "path = " <<  path << ENDL;
	int res;

	res = access(path, mask);
	if (res == -1)
		return -errno;

	return 0;
}

int xmp_readlink(const char *path, char *buf, size_t size)
{	
	//LOG << "path = " << path << ENDL;
	int res;

	res = readlink(path, buf, size - 1);
	if (res == -1)
		return -errno;

	buf[res] = '\0';
	return 0;
}


int xmp_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
		       off_t offset, struct fuse_file_info *fi)
{
	//LOG << "path = " << path << ", offset = " << offset << ENDL;
	DIR *dp;
	struct dirent *de;

	(void) offset;
	(void) fi;

	dp = opendir(path);
	if (dp == NULL)
		return -errno;

	while ((de = readdir(dp)) != NULL) {		
		if (filler(buf, de->d_name, NULL, 0))
			break;
	}

	closedir(dp);
	return 0;
}

int xmp_mknod(const char *path, mode_t mode, dev_t rdev)
{	
	//LOG << "path = " << path << ENDL;
	int res;

	/* On Linux this could just be 'mknod(path, mode, rdev)' but this
	   is more portable */
	if (S_ISREG(mode)) {
		res = open(path, O_CREAT | O_EXCL | O_WRONLY, mode);
		if (res >= 0)
			res = close(res);
	} else if (S_ISFIFO(mode))
		res = mkfifo(path, mode);
	else
		res = mknod(path, mode, rdev);
	if (res == -1)
		return -errno;
	chmod(path, 0644);
	return 0;
}

int xmp_mkdir(const char *path, mode_t mode)
{
	//LOG << "path = " <<  path << ENDL;
	int res;

	res = mkdir(path, mode);
	if (res == -1)
		return -errno;

	return 0;
}

int xmp_unlink(const char *path)
{
	//LOG << "path = " << path << ENDL;
	int res;

	res = unlink(path);
	if (res == -1)
		return -errno;

	return 0;
}

int xmp_rmdir(const char *path)
{
	//LOG << "path = " << path << ENDL;
	int res;

	res = rmdir(path);
	if (res == -1)
		return -errno;

	return 0;
}

int xmp_symlink(const char *from, const char *to)
{
	//LOG << ENDL;
	int res;

	res = symlink(from, to);
	if (res == -1)
		return -errno;

	return 0;
}

int xmp_rename(const char *from, const char *to)
{
	//LOG << ENDL;
	int res;

	res = rename(from, to);
	if (res == -1)
		return -errno;

	return 0;
}

int xmp_link(const char *from, const char *to)
{
	//LOG << ENDL;
	int res;

	res = link(from, to);
	if (res == -1)
		return -errno;

	return 0;
}

int xmp_chmod(const char *path, mode_t mode)
{
	//LOG << ENDL;
	int res;

	res = chmod(path, mode);
	if (res == -1)
		return -errno;

	return 0;
}

int xmp_chown(const char *path, uid_t uid, gid_t gid)
{
	//LOG << ENDL;
	int res;

	res = lchown(path, uid, gid);
	if (res == -1)
		return -errno;

	return 0;
}

int xmp_truncate(const char *path, off_t size)
{
	//LOG << ENDL;
	int res;

	res = truncate(path, size);
	if (res == -1)
		return -errno;

	return 0;
}

int xmp_utimens(const char *path, const struct timespec ts[2])
{
	//LOG << ENDL;
	int res;
//	struct timeval tv[2];
//
//	tv[0].tv_sec = ts[0].tv_sec;
//	tv[0].tv_usec = ts[0].tv_nsec / 1000;
//	tv[1].tv_sec = ts[1].tv_sec;
//	tv[1].tv_usec = ts[1].tv_nsec / 1000;
	(void)ts;
	res = utimes(path, NULL);
	if (res == -1)
		return -errno;

	return 0;
}

int xmp_open(const char *path, struct fuse_file_info *fi)
{
	//LOG << ENDL;
	int res;

	res = open(path, fi->flags);
	if (res == -1)
		return -errno;

	//close(res);
	fi->fh = (int64_t)res;
	return 0;
}

int xmp_read(const char *path, char *buf, size_t size, off_t offset,
		    struct fuse_file_info *fi)
{
	//LOG_GRE << "path = " << path << ", offset = " << offset << ", size = " << size << ENDL;
	
	int fd = (int)fi->fh;
	int res;


	//fd = open(path, O_RDONLY);
	//if (fd == -1)
		//return -errno;

	res = pread(fd, buf, size, offset);
	if (res == -1)
		res = -errno;

	//close(fd);
	return res;
}

int xmp_write(const char *path, const char *buf, size_t size,
		     off_t offset, struct fuse_file_info *fi)
{
	//LOG << "path = " << path << ", size = " << size <<", offset = " << offset << ENDL;
	int fd = (int)fi->fh;
	int res;

	//(void) fi;
	//fd = open(path, O_WRONLY);
	if (fd == -1)
		return -errno;

	res = pwrite(fd, buf, size, offset);
	if (res == -1)
		res = -errno;

	//close(fd);
	return res;
}

int xmp_statfs(const char *path, struct statvfs *stbuf)
{	
	//LOG << "path = " << path << ENDL;
	int res;

	res = statvfs(path, stbuf);
	if (res == -1)
		return -errno;

	return 0;
}

int xmp_release(const char *path, struct fuse_file_info *fi)
{
	/* Just a stub.	 This method is optional and can safely be left
	   unimplemented */
	//LOG << "path = " << path << ENDL;
	(void) path;
	(void) fi;
	return 0;
}

int xmp_fsync(const char *path, int isdatasync,
		     struct fuse_file_info *fi)
{
	/* Just a stub.	 This method is optional and can safely be left
	   unimplemented */
	//LOG << "path = " << path << ENDL;
	(void) path;
	(void) isdatasync;
	(void) fi;
	return 0;
}




